﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Badger.Vhdl
{
  public abstract class TypePropertyInfo
  {
    private TypeProperties tag;
    public TypeProperties Tag
    {
      get
      {
        return tag;
      }
    }

    public TypePropertyInfo(TypeProperties tag)
    {
      this.tag = tag;
    }
  }

  public class ArrayProperty : TypePropertyInfo
  {
    private Type elementType;
    public Type ElementType
    {
      get
      {
        return elementType;
      }
    }

    public ArrayProperty(Type elementType) : base(TypeProperties.Array)
    {
      this.elementType = elementType;
    }
  }

  public class EnumerationProperty : TypePropertyInfo
  {
    private Type subType;
    public Type SubType
    {
      get
      {
        return subType;
      }
    }

    public EnumerationProperty(Type subType) :  base(TypeProperties.Enumeration)
    {
      this.subType = subType;
    }
  }

  public class Undefined : Type
  {
    public Undefined() : base("undefined")
    {
    }
  }

  public class Type
  {
    private int id;

    private string name;
    public string Name
    {
      get
      {
        return name;
      }

      set
      {
        name = value;
      }
    }

    private Dictionary<TypeProperties, TypePropertyInfo> properties =
      new Dictionary<TypeProperties, TypePropertyInfo>();

    // reference to "type registry"
    private List<Type> types = new List<Type>();

    private void setType(Type type)
    {
      if(!(types.Contains(type)))
        types.Add(type);
    }

    public bool IsType(Type t)
    {
      foreach (Type type in t.types)
        if (!this.types.Contains(type))
          return false;

      return true;
    }

    public bool IsExactType(Type t)
    {
      return IsType(t) && t.IsType(this);
    }

    public bool HasProperty(TypeProperties property)
    {
      return properties.ContainsKey(property);
    }

    public TypePropertyInfo GetPropertyInfo(TypeProperties property)
    {
      return properties[property];
    }

    protected void AddProperty(TypePropertyInfo tpi)
    {
      if (properties.ContainsKey(tpi.Tag))
        throw new Exception("Property already set");

      properties.Add(tpi.Tag, tpi);
    }

    public Type(string name) : 
      this(name, new TypePropertyInfo[] {}, new Type[] {})
    {
    }

    public Type(string name, TypePropertyInfo[] properties) : 
      this(name, properties, new Type[] {})
    {
    }

    public Type(string name, TypePropertyInfo[] properties, Type[] types)
    {
      this.name = name;

      foreach (TypePropertyInfo tpi in properties)
        if (!this.properties.ContainsKey(tpi.Tag))
          this.properties.Add(tpi.Tag, tpi);

      foreach (Type type in types)
        this.types.Add(type);

      id = TypeRegistry.RegisterType(this);

      setType(this);
    }
  }
}
